﻿using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Windows.Input;
using CredentialsManager.Helpers;
using CredentialsManager.Properties;
using MVVMFoundation;

namespace CredentialsManager.ViewModels
{
    public class UpdateUserViewModel : UserViewModel
    {
        #region Private classes

        private class SetupWorkerInput
        {
            public string Application { get; set; }
            public string UserName { get; set; }
        }

        private class UpdateWorkerInput : SetupWorkerInput
        {
            public string Email { get; set; }
            public bool IsApproved { get; set; }
            public bool IsLockedOut { get; set; }
        }

        #endregion

        #region Private member variables

        private bool m_IsLockedOut;
        private BackgroundWorker m_SetupWorker;
        private BackgroundWorker m_UpdateWorker;
        private RelayCommand m_UpdateCommand;

        #endregion

        #region Constructor

        public UpdateUserViewModel(string displayName, string application, string userName,
            PasswordSettings passwordSettings)
            : base(displayName, application, passwordSettings)
        {
            Debug.Assert(this.IsUserNameEditable);
            this.UserName = userName;
            this.IsUserNameEditable = false;

            m_SetupWorker = new BackgroundWorker();
            m_SetupWorker.Initialise(m_SetupWorker_DoWork,
                m_SetupWorker_RunWorkerCompleted, null, false);

            m_UpdateWorker = new BackgroundWorker();
            m_UpdateWorker.Initialise(m_UpdateWorker_DoWork,
                m_UpdateWorker_RunWorkerCompleted, null, false);

            var input = new SetupWorkerInput() { Application = application, UserName = userName };

            this.ProgressMessage = string.Format(
                Resources.RetrievingUserInfoProgressMessage.ToString(), userName);
            this.IsLoading = true;
            m_SetupWorker.RunWorkerAsync(input);
        }

        public UpdateUserViewModel(string application, string userName,
            PasswordSettings passwordSettings)
            : this(Resources.UpdateUserWindowTitle,
                application, userName, passwordSettings)
        { }

        #endregion

        #region Background worker handlers

        private void m_SetupWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var input = e.Argument as SetupWorkerInput;
            Debug.Assert(input != null);

            var proxy = ProxyFactory.Create<MembershipManagerClient, IMembershipManager>(
                ServiceAddressList.CredentialsService);

            try
            {
                var userInfo = proxy.GetUserInfo(input.Application, input.UserName);
                e.Result = userInfo;
            }
            finally
            {
                ProxyFactory.Cleanup<MembershipManagerClient, IMembershipManager>(proxy);
            }
        }

        private void m_SetupWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ErrorHandler.HandleNonSpecificWCFException(e.Error, this.DisplayName);
            }
            else
            {
                var userInfo = e.Result as UserInfo;
                Debug.Assert(userInfo != null);

                this.Email = userInfo.Email;
                this.IsApproved = userInfo.IsApproved;
                this.IsLockedOut = userInfo.IsLockedOut;                
            }

            this.IsLoading = false;
        }

        private void m_UpdateWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var input = e.Argument as UpdateWorkerInput;
            Debug.Assert(input != null);

            var proxy = ProxyFactory.Create<MembershipManagerClient, IMembershipManager>(
                ServiceAddressList.CredentialsService);

            try
            {
                proxy.UpdateUser(input.Application, input.UserName, input.Email, 
                    input.IsApproved, input.IsLockedOut);
            }
            finally
            {
                ProxyFactory.Cleanup<MembershipManagerClient, IMembershipManager>(proxy);
            }
        }

        private void m_UpdateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ErrorHandler.HandleNonSpecificWCFException(e.Error, this.DisplayName);
            }
            else
            {
                this.OnRequestClose();
            }

            this.IsLoading = false;
        }

        #endregion

        #region Public properties

        public bool IsLockedOut
        {
            get
            {
                return m_IsLockedOut;
            }
            set
            {
                m_IsLockedOut = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
            }
        }

        #endregion

        #region Private methods

        private void Update()
        {
            var input = new UpdateWorkerInput()
            {
                Application = this.Application,
                UserName = this.UserName,
                Email = this.Email,
                IsApproved = this.IsApproved,
                IsLockedOut = this.IsLockedOut
            };

            this.ProgressMessage = string.Format(
                Resources.UpdateUserProgressMessage.ToString(), this.UserName);
            this.IsLoading = true;
            m_UpdateWorker.RunWorkerAsync(input);
        }

        #endregion

        #region Commands

        public ICommand UpdateCommand
        {
            get
            {
                return m_UpdateCommand ?? (m_UpdateCommand = new RelayCommand(
                    param => this.Update()));
            }
        }

        #endregion
    }
}
